package com.midea.thread;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * @description：
 * Q:耗时太长的原因是什么呢
 * A:程序中的 request方法使用 synchronized关键字修饰，保证了并发情况下， request方法同一时刻许一个线程进入，
 * request加锁相当于串行执行了， count的结果和我们预期的一致，只是耗时太长了
 * Q：如何解决耗时长的问题？
 * A：count +t实际上是由3步来完成！（jVm执行引擎）
 *      1.获取 count的值，记做A : A= count
 *      2.将A值+1，得到B : B=A+1
 *      3。将B值赋值给count
 *      升级第3步的实现：
 *          1.获取锁
 *          2.获取以下 count最新的值，记做LV
 *          3.判断LV是否等于A，如果相等，则将B的值赋值给 count，并返回true，否则返回 false
 *          4.释放锁
 * @author: wangwl23
 * @create: 2021-08-08 18:56
 */
public class CasDemo2 {
    //总访问量
    //保证可见性，从主存中拿数据
    volatile static int count = 0;

    //模拟访问的方法
    public static void request() throws InterruptedException {
        //模拟耗时5秒钟
        TimeUnit.MILLISECONDS.sleep(5);
        //count ++;
        int expectCount;
        while (!compareAndSwap((expectCount = getCount()), expectCount + 1)) {

        }
    }

    /**
     * @param expectCount 期望值count
     * @param newCount    需要给count赋值的新值
     * @return 成功返回true，失败返回false
     */
    public static synchronized boolean compareAndSwap(int expectCount, int newCount) {
        if (getCount() == expectCount) {
            count = newCount;
            return true;
        }
        return false;
    }

    private static int getCount() {
        return count;
    }

    public static void main(String[] args) throws InterruptedException {
        long startTime = System.currentTimeMillis();
        int threadSize = 100;
        CountDownLatch countDownLatch = new CountDownLatch(threadSize);
        for (int i = 0; i < threadSize; i++) {
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    //模拟用户行为，每个用户访问10次网站；
                    try {
                        for (int j = 0; j < 10; j++) {
                            request();
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        countDownLatch.countDown();
                    }
                }
            });
            thread.start();
        }
        //保证100个线程执行结束之后，在执行后面代码
        countDownLatch.await();
        long endTime = System.currentTimeMillis();
        System.out.println(Thread.currentThread().getName() + "耗时：" + (endTime - startTime) + ",count = " + count);
    }
}
